use failure::Fail;
use actix_web::{
    http::StatusCode, Query, FromRequest,
    dev::Handler, HttpRequest, ResponseError, HttpResponse,
};

pub struct FailHandler;

impl FailHandler {
    pub fn new() -> Self {
        FailHandler
    }
}

impl<S> Handler<S> for FailHandler {
    type Result = Result<String, FailError>;

    fn handle(&self, req: &HttpRequest<S>) -> Self::Result {
        #[derive(Debug, Serialize, Deserialize)]
        struct DebugFlag {
            debug: i32,
            debug2: i32,
        }

        impl Default for DebugFlag {
            fn default() -> Self {
                Self {
                    debug: 0,
                    debug2: 0,
                }
            }
        }

        // Query<T>(T)
        let debug = Query::<DebugFlag>::extract(req)
            .map(|x| {
                x.into_inner()
            }).unwrap_or(DebugFlag {
                debug: -1,
                debug2: -1,
            });

        println!("{:?}", debug);

        println!("request query: {:?}", req.query());
        println!("request query get: {:?}", req.query().get("debug"));

        match debug.debug {
            0 => Ok(format!("{:?}", req)),
            1 => Err(FailError::ErrorTypeOne),
            2 => Err(FailError::ErrorTypeTwo),
            _ => Err(FailError::ErrorUnknown),
        }
    }
}

#[derive(Debug, Fail)]
pub enum FailError {
    #[fail(display="error type one")]
    ErrorTypeOne,
    #[fail(display="error type two")]
    ErrorTypeTwo,
    #[fail(display="error type unknown")]
    ErrorUnknown,
}

impl ResponseError for FailError {
    fn error_response(&self) -> HttpResponse {
        match *self {
            FailError::ErrorTypeOne => HttpResponse::new(StatusCode::BAD_REQUEST),
            FailError::ErrorTypeTwo => HttpResponse::new(StatusCode::IM_A_TEAPOT),
            FailError::ErrorUnknown => HttpResponse::new(StatusCode::NOT_FOUND),
        }
    }
}
